#!/usr/bin/env python3
"""
AsciiDoc文档托管与在线预览平台
支持文件上传、实时预览、多人协作等功能
"""

import os
import json
import uuid
import hashlib
from datetime import datetime
from pathlib import Path
from flask import Flask, render_template, request, jsonify, send_file, redirect, url_for
from werkzeug.utils import secure_filename
import subprocess
import shutil

# 配置
UPLOAD_FOLDER = 'static/uploads'
ALLOWED_EXTENSIONS = {'adoc', 'asciidoc', 'asc'}
MAX_CONTENT_LENGTH = 16 * 1024 * 1024  # 16MB

app = Flask(__name__)
app.config['UPLOAD_FOLDER'] = UPLOAD_FOLDER
app.config['MAX_CONTENT_LENGTH'] = MAX_CONTENT_LENGTH

# 确保上传目录存在
os.makedirs(UPLOAD_FOLDER, exist_ok=True)
os.makedirs('docs', exist_ok=True)

# 文档数据库
DOCS_DB = 'docs/docs_db.json'

def init_db():
    """初始化文档数据库"""
    if not os.path.exists(DOCS_DB):
        with open(DOCS_DB, 'w', encoding='utf-8') as f:
            json.dump({
                "documents": {},
                "versions": {},
                "comments": {},
                "permissions": {}
            }, f, ensure_ascii=False, indent=2)

def load_db():
    """加载数据库"""
    with open(DOCS_DB, 'r', encoding='utf-8') as f:
        return json.load(f)

def save_db(data):
    """保存数据库"""
    with open(DOCS_DB, 'w', encoding='utf-8') as f:
        json.dump(data, f, ensure_ascii=False, indent=2)

def allowed_file(filename):
    """检查文件扩展名是否允许"""
    return '.' in filename and \
           filename.rsplit('.', 1)[1].lower() in ALLOWED_EXTENSIONS

def render_adoc_to_html(adoc_path, html_path):
    """将AsciiDoc渲染为HTML"""
    try:
        cmd = [
            'asciidoctor',
            '-b', 'html5',
            '-o', html_path,
            adoc_path
        ]
        result = subprocess.run(cmd, capture_output=True, text=True)
        return result.returncode == 0
    except Exception as e:
        print(f"渲染错误: {e}")
        return False

@app.route('/')
def index():
    """首页 - 文档列表"""
    db = load_db()
    documents = db.get('documents', {})
    
    # 获取每个文档的最新版本
    doc_list = []
    for doc_id, doc_info in documents.items():
        versions = db.get('versions', {}).get(doc_id, [])
        if versions:
            latest = max(versions, key=lambda x: x['timestamp'])
            doc_info.update({
                'id': doc_id,
                'latest_version': latest['version'],
                'updated_at': latest['timestamp']
            })
        else:
            doc_info.update({
                'id': doc_id,
                'latest_version': '1.0',
                'updated_at': doc_info.get('created_at', '')
            })
        doc_list.append(doc_info)
    
    return render_template('index.html', documents=doc_list)

@app.route('/upload', methods=['GET', 'POST'])
def upload():
    """上传新文档"""
    if request.method == 'POST':
        if 'file' not in request.files:
            return jsonify({'error': '没有选择文件'}), 400
        
        file = request.files['file']
        if file.filename == '':
            return jsonify({'error': '没有选择文件'}), 400
        
        if file and allowed_file(file.filename):
            # 生成唯一ID
            doc_id = str(uuid.uuid4())
            filename = secure_filename(file.filename)
            
            # 保存文件
            file_path = os.path.join(app.config['UPLOAD_FOLDER'], f"{doc_id}_{filename}")
            file.save(file_path)
            
            # 渲染为HTML
            html_filename = f"{doc_id}.html"
            html_path = os.path.join('static/uploads', html_filename)
            if render_adoc_to_html(file_path, html_path):
                # 更新数据库
                db = load_db()
                db['documents'][doc_id] = {
                    'filename': filename,
                    'title': filename.rsplit('.', 1)[0],
                    'description': request.form.get('description', ''),
                    'created_at': datetime.now().isoformat(),
                    'author': request.form.get('author', '匿名用户'),
                    'file_path': file_path,
                    'html_path': html_path
                }
                
                # 添加版本记录
                if doc_id not in db['versions']:
                    db['versions'][doc_id] = []
                db['versions'][doc_id].append({
                    'version': '1.0',
                    'timestamp': datetime.now().isoformat(),
                    'file_path': file_path,
                    'html_path': html_path,
                    'changes': '初始版本'
                })
                
                save_db(db)
                
                return jsonify({
                    'success': True,
                    'doc_id': doc_id,
                    'redirect': url_for('view_document', doc_id=doc_id)
                })
            else:
                return jsonify({'error': '文档渲染失败'}), 500
    
    return render_template('upload.html')

@app.route('/document/<doc_id>')
def view_document(doc_id):
    """查看文档"""
    db = load_db()
    documents = db.get('documents', {})
    
    if doc_id not in documents:
        return "文档不存在", 404
    
    doc = documents[doc_id]
    versions = db.get('versions', {}).get(doc_id, [])
    comments = db.get('comments', {}).get(doc_id, [])
    
    return render_template('viewer.html', 
                         document=doc, 
                         versions=versions, 
                         comments=comments,
                         doc_id=doc_id)

@app.route('/api/document/<doc_id>/content')
def get_document_content(doc_id):
    """获取文档内容"""
    db = load_db()
    documents = db.get('documents', {})
    
    if doc_id not in documents:
        return jsonify({'error': '文档不存在'}), 404
    
    doc = documents[doc_id]
    
    try:
        with open(doc['file_path'], 'r', encoding='utf-8') as f:
            content = f.read()
        return jsonify({'content': content})
    except Exception as e:
        return jsonify({'error': str(e)}), 500

@app.route('/api/document/<doc_id>/comments', methods=['GET', 'POST'])
def handle_comments(doc_id):
    """处理评论"""
    db = load_db()
    
    if request.method == 'POST':
        data = request.json
        comment = {
            'id': str(uuid.uuid4()),
            'author': data.get('author', '匿名用户'),
            'content': data['content'],
            'timestamp': datetime.now().isoformat(),
            'line': data.get('line', None)
        }
        
        if doc_id not in db['comments']:
            db['comments'][doc_id] = []
        
        db['comments'][doc_id].append(comment)
        save_db(db)
        
        return jsonify({'success': True, 'comment': comment})
    
    comments = db.get('comments', {}).get(doc_id, [])
    return jsonify({'comments': comments})

@app.route('/api/document/<doc_id>/search')
def search_document(doc_id):
    """在文档中搜索"""
    query = request.args.get('q', '').lower()
    
    db = load_db()
    documents = db.get('documents', {})
    
    if doc_id not in documents:
        return jsonify({'error': '文档不存在'}), 404
    
    doc = documents[doc_id]
    
    try:
        with open(doc['file_path'], 'r', encoding='utf-8') as f:
            lines = f.readlines()
        
        results = []
        for i, line in enumerate(lines):
            if query in line.lower():
                results.append({
                    'line': i + 1,
                    'content': line.strip()
                })
        
        return jsonify({'results': results})
    except Exception as e:
        return jsonify({'error': str(e)}), 500

@app.route('/api/document/<doc_id>/export/<format>')
def export_document(doc_id, format):
    """导出文档"""
    db = load_db()
    documents = db.get('documents', {})
    
    if doc_id not in documents:
        return jsonify({'error': '文档不存在'}), 404
    
    doc = documents[doc_id]
    
    if format == 'pdf':
        # 使用asciidoctor-pdf导出PDF
        pdf_path = f"static/uploads/{doc_id}.pdf"
        cmd = [
            'asciidoctor-pdf',
            '-o', pdf_path,
            doc['file_path']
        ]
        result = subprocess.run(cmd, capture_output=True, text=True)
        
        if result.returncode == 0:
            return send_file(pdf_path, as_attachment=True)
        else:
            return jsonify({'error': 'PDF导出失败'}), 500
    
    elif format == 'html':
        return send_file(doc['html_path'], as_attachment=True)
    
    elif format == 'epub':
        # 使用asciidoctor-epub3导出EPUB
        epub_path = f"static/uploads/{doc_id}.epub"
        cmd = [
            'asciidoctor-epub3',
            '-o', epub_path,
            doc['file_path']
        ]
        result = subprocess.run(cmd, capture_output=True, text=True)
        
        if result.returncode == 0:
            return send_file(epub_path, as_attachment=True)
        else:
            return jsonify({'error': 'EPUB导出失败'}), 500
    
    return jsonify({'error': '不支持的格式'}), 400

@app.route('/api/documents')
def list_documents():
    """获取文档列表"""
    db = load_db()
    documents = db.get('documents', {})
    
    doc_list = []
    for doc_id, doc_info in documents.items():
        versions = db.get('versions', {}).get(doc_id, [])
        if versions:
            latest = max(versions, key=lambda x: x['timestamp'])
            doc_info['latest_version'] = latest['version']
            doc_info['updated_at'] = latest['timestamp']
        
        doc_list.append({
            'id': doc_id,
            'title': doc_info.get('title', ''),
            'description': doc_info.get('description', ''),
            'author': doc_info.get('author', ''),
            'created_at': doc_info.get('created_at', ''),
            'updated_at': doc_info.get('updated_at', '')
        })
    
    return jsonify({'documents': doc_list})

if __name__ == '__main__':
    init_db()
    app.run(debug=True, host='0.0.0.0', port=5000)
